package handler

import (
	"fmt"
	"go-devops/common"
	"go-devops/domain/dto"
	"log"
	"path/filepath"
	"strings"
)

type DockerTaskHandler struct {
	CommonTaskHandler
}

func NewDockerTaskHandler() *DockerTaskHandler {
	return &DockerTaskHandler{
		CommonTaskHandler: CommonTaskHandler{},
	}
}

type DockerData struct {
	SecretName string `json:"secretName"`
	Name       string `json:"name"`
	Version    string `json:"version"`
	BuildPath  string `json:"buildPath"`
	DockerFile string `json:"dockerFile"`
	Registry   string `json:"registry"`
	AfterCmd   string `json:"afterCmd"`
	WorkDir    string `json:"workDir"`
}

func getDockerData(context *dto.NodeContext) DockerData {
	data := context.TaskData.Data
	jsonString := common.JsonString(data)
	var dockerData DockerData
	dockerData.DockerFile = common.DockerFile
	dockerData.Version = common.DockerVersion
	dockerData.BuildPath = common.BuildPath
	common.ParseJson(jsonString, &dockerData)
	return dockerData
}

func (c DockerTaskHandler) Stop(context *dto.NodeContext) error {
	context.StopFlag = true
	return nil
}

func (c DockerTaskHandler) HandleNode(nodeContext *dto.NodeContext) error {
	return c.Handle(nodeContext, func() error {
		data := getDockerData(nodeContext)
		workspace := nodeContext.Workspace
		if len(data.WorkDir) > 0 && strings.HasPrefix(data.WorkDir, "/") {
			workspace = workspace + data.WorkDir
		} else {
			workspace = filepath.Join(workspace, data.WorkDir)
		}
		log.Printf("工作目录：%s\n", workspace)
		sendMsg(nodeContext, true, fmt.Sprintf("工作目录：%s", workspace))

		dockerFile := getDockerFile(workspace, data)
		log.Printf("dockerFile：%s\n", dockerFile)
		sendMsg(nodeContext, true, fmt.Sprintf("dockerFile：%s", dockerFile))

		tag := data.Name
		if len(data.Registry) > 0 {
			tag = filepath.Join(data.Registry, data.Name)
		}
		log.Printf("docker tag：%s\n", tag)
		sendMsg(nodeContext, true, fmt.Sprintf("docker tag：%s", tag))

		dockerBuildCmd := fmt.Sprintf("docker build -t %s:%s -f %s %s", tag, data.Version, dockerFile, data.BuildPath)
		if err := ExecCmd(nodeContext, dockerBuildCmd, workspace, true); err != nil {
			return err
		}

		if len(data.SecretName) > 0 {
			secret, err := GetSecret(common.DOCKER, data.SecretName)
			if err != nil {
				return err
			}

			loginCmd := fmt.Sprintf("docker login -u %s -p %s %s", secret.SecretKey, secret.SecretValue, data.Registry)
			pushCmd := fmt.Sprintf("docker push %s:%s", tag, data.Version)

			sendMsg(nodeContext, true, fmt.Sprintf("开始推送镜像 %s:%s", tag, data.Version))
			if err := ExecCmd(nodeContext, loginCmd+" && "+pushCmd, workspace, false); err != nil {
				return err
			}
		}

		if len(data.AfterCmd) > 0 {
			if err := ExecCmd(nodeContext, data.AfterCmd, workspace, true); err != nil {
				return err
			}
		}
		return nil
	})
}

func getDockerFile(workspace string, data DockerData) string {
	dockerFile := data.DockerFile
	if len(dockerFile) <= 0 {
		return common.DockerFile
	}

	if strings.Contains(dockerFile, common.EnvWorkspace) {
		return strings.ReplaceAll(dockerFile, common.EnvWorkspace, workspace)
	}

	return dockerFile
}
